﻿using System;
using System.Collections.Generic;
using System.Text;

using GeometryCSharp;
using AGHFiraPlayer.Drivers;

namespace AGHFiraPlayer.Strategies.StrategiesImpl
{
    class SupporterStrategy : AbstractStrategy
    {
        RobotController shooter = null;
        RobotController passer = null;
        RobotController supporter = null;
        private List<RobotController> sortedOpponents;
        private List<RobotController> sortedRobots;
        private double opponentBallDistance, robotBallDistance;
        private Point2D ballPos;
        private const int MAX_SCORE = 100;

        public SupporterStrategy(ref AGHDriver driver)
        {
            involvedRobots = new List<RobotController>();
            this.driver = driver;
        }

        override public int applicabilityLevel(ref List<IStrategy> choosenStrategies)
        {
            currentApplicability = MAX_APPLICABILITY / 3;
            determineEssentialPlayers(ref choosenStrategies);
            ballPos = new Point2D(Predicator.firaDriver.ballX, Predicator.firaDriver.ballY);
            sortedRobots = Predicator.getRobotListSortedByDistanceFromGivenPoint(getUnoccupiedRobots(), ballPos);
            involvedRobots.Clear();
            involvedRobots.Add(sortedRobots[0]);
            if (passer != null || shooter != null)
                currentApplicability *= 2;

            return currentApplicability;
        }

        private void determineEssentialPlayers(ref List<IStrategy> choosenStrategies)
        {
            shooter = null;
            passer = null;
            supporter = null;
            foreach (IStrategy strat in choosenStrategies)
            {
                if (strat.GetType().Name.Equals(typeof(SimpleShotStrategy).GetType().Name))
                {
                    shooter = strat.getInvolvedRobots()[0];
                }
                if (strat.GetType().Name.Equals(typeof(SimplePassStrategy).GetType().Name))
                {
                    passer = strat.getInvolvedRobots()[0];
                }
                if (strat.GetType().Name.Equals(typeof(SupporterStrategy).GetType().Name))
                {
                    supporter = strat.getInvolvedRobots()[0];
                }
            }
        }

        override public void execute()
        {
            Point2D point, rememberedPoint = null;
            double maxScore = 0, score = 0;
            int xMax = (int)(AGHDriver.pitchArea.Width / AGHDriver.ROBOT_DIAMETER);
            int yMax = (int)(AGHDriver.pitchArea.Height / AGHDriver.ROBOT_DIAMETER);

            for (int x = 1; x < xMax; x++)
                for (int y = 1; y < yMax; y++)
                {
                    point = new Point2D(AGHDriver.ROBOT_DIAMETER * xMax, AGHDriver.ROBOT_DIAMETER * yMax);
                    List<RobotController> sortedRobotList = Predicator.getAllRobotListSortedByDistanceFromGivenPoint(point);
                    score = calculateScore(point, sortedRobotList);
                    if (score > maxScore)
                    {
                        rememberedPoint = point;
                        maxScore = score;
                    }
                }

            GoalKeeperDriver.DriveVelocity(involvedRobots[0].robotState, rememberedPoint.x, rememberedPoint.y, PotencialDriver.maxVelocity);
        }

        private double calculateScore(Point2D point, List<RobotController> sortedRobotList)
        {
            double score = MAX_SCORE;
            double distance1 = sortedRobotList[0].Position.GetDistance(point);
            double distance2 = sortedRobotList[1].Position.GetDistance(point);
            double distance3 = sortedRobotList[2].Position.GetDistance(point);

            score -= 3 / distance1;
            score -= 2 / distance2;
            score -= 1 / distance3;

            if (point.x < AGHDriver.pitchArea.Width / 2)
                score /= 2;

            Geometry.Point2D upperPost = new Geometry.Point2D(AGHDriver.target.x, AGHDriver.target.y + 2 * AGHDriver.ROBOT_DIAMETER);
            Geometry.Point2D lowerPost = new Geometry.Point2D(AGHDriver.target.x, AGHDriver.target.y - 2 * AGHDriver.ROBOT_DIAMETER);
            Geometry.Polygon2D polygon = new Geometry.Polygon2D(new Geometry.Point2D[] { new Geometry.Point2D(point.x, point.y), upperPost, lowerPost });
            foreach (RobotController oponent in driver.Oponents)
            {
                Geometry.Point2D oponentPosition = new Geometry.Point2D(oponent.robotState.x, oponent.robotState.y);
                if (polygon.Contains(oponentPosition))
                {
                    score *= 0.8;
                }
            }

            return score;
        }
    }
}
